import { connect } from 'amqplib';
import { EventEmitter } from 'events';
import {
  RabbitMQConfig,
  ConnectionPoolConfig,
  ManagedConnection,
  ConnectionOptions,
  ConnectionError,
  Logger,
} from '@/types';
import { createLogger } from '@/utils/logger';

interface PooledConnection extends ManagedConnection {
  id: string;
  createdAt: number;
  usageCount: number;
}

// 扩展的连接池统计接口
export interface ExtendedConnectionPoolStats {
  totalConnections: number;
  availableConnections: number;
  busyConnections: number;
  poolSize: number;
  pendingRequests: number;
  connectionCreationRate: number;
  connectionFailureRate: number;
  averageWaitTime: number;
  peakConnections: number;
  idleConnections: number;
  connectionUtilization: number;
  lastScaleEvent?: {
    timestamp: number;
    action: 'scale-up' | 'scale-down';
    fromSize: number;
    toSize: number;
    reason: string;
  };
}

// 等待连接的请求
interface PendingRequest {
  resolve: (connection: PooledConnection) => void;
  reject: (error: Error) => void;
  timestamp: number;
}

export class ConnectionPool extends EventEmitter {
  private readonly config: RabbitMQConfig;
  private readonly poolConfig: ConnectionPoolConfig;
  private readonly logger: Logger;
  private readonly connections: Map<string, PooledConnection> = new Map();
  private readonly availableConnections: string[] = [];
  private readonly busyConnections: Set<string> = new Set();
  private isShuttingDown = false;
  private reapTimer?: NodeJS.Timeout;

  // 动态扩展相关
  private readonly pendingRequests: PendingRequest[] = [];
  private currentPoolSize: number;
  private peakConnections = 0;

  // 统计信息
  private connectionCreationCount = 0;
  private connectionFailureCount = 0;
  private totalWaitTime = 0;
  private waitTimeCount = 0;
  private lastStatsReset = Date.now();
  private lastScaleEvent?: ExtendedConnectionPoolStats['lastScaleEvent'];

  constructor(
    config: RabbitMQConfig,
    poolConfig: Partial<ConnectionPoolConfig> = {},
    logger?: Logger
  ) {
    super();
    this.config = config;
    this.poolConfig = {
      poolSize: 10,
      acquireTimeout: 20000,  // 20秒获取超时 (更合理的等待时间)
      idleTimeout: 600000,    // 10分钟空闲超时 (更长的保持时间)
      reapInterval: 120000,   // 2分钟清理间隔 (减少清理频率)
      // 动态扩展默认配置
      minPoolSize: 3,         // 最小3个连接保证基本可用性
      maxPoolSize: 30,        // 最大30个连接，避免过度消耗资源
      dynamicScaling: true,   // 默认启用动态扩展
      scaleUpThreshold: 5,    // 5个等待请求时扩展
      scaleDownThreshold: 8,  // 8个空闲连接时收缩
      scaleUpStep: 3,         // 每次扩展3个连接，更快响应负载
      scaleDownStep: 2,       // 每次收缩2个连接，更快释放资源
      ...poolConfig,
    };
    this.logger = logger ?? createLogger('ConnectionPool');

    // 初始化动态扩展属性
    this.currentPoolSize = this.poolConfig.poolSize;

    this.startReaper();
  }

  public async getConnection(): Promise<ManagedConnection> {
    if (this.isShuttingDown) {
      throw new ConnectionError('Connection pool is shutting down');
    }

    // 直接调用 acquireConnection，它内部已经有超时处理
    return await this.acquireConnection();
  }

  public async returnConnection(connection: ManagedConnection): Promise<void> {
    const pooledConnection = Array.from(this.connections.values()).find(
      conn => conn.connection === connection.connection
    );

    if (!pooledConnection) {
      this.logger.warn('Attempted to return unknown connection');
      return;
    }

    if (!pooledConnection.isActive || (pooledConnection.connection as any).connection?.destroyed) {
      await this.removeConnection(pooledConnection.id);
      return;
    }

    this.busyConnections.delete(pooledConnection.id);
    pooledConnection.lastUsed = Date.now();

    // 优先处理等待的请求
    if (this.pendingRequests.length > 0) {
      const pendingRequest = this.pendingRequests.shift()!;
      this.busyConnections.add(pooledConnection.id);
      pooledConnection.usageCount++;
      pooledConnection.lastUsed = Date.now();

      this.logger.debug(`Connection ${pooledConnection.id} directly assigned to pending request`);
      pendingRequest.resolve(pooledConnection);
    } else {
      // 没有等待的请求，将连接返回到可用池
      this.availableConnections.push(pooledConnection.id);

      this.logger.debug(`Connection ${pooledConnection.id} returned to pool`);
      this.emit('connectionReturned', pooledConnection);

      // 检查是否需要收缩连接池
      if (this.shouldScaleDown()) {
        await this.scaleDown();
      }
    }
  }

  private async acquireConnection(): Promise<ManagedConnection> {
    const startTime = Date.now();

    // Try to get an available connection
    const connectionId = this.availableConnections.pop();

    if (connectionId) {
      const connection = this.connections.get(connectionId);
      if (connection && connection.isActive) {
        this.busyConnections.add(connectionId);
        connection.usageCount++;
        connection.lastUsed = Date.now();
        this.logger.debug(`Reusing connection ${connectionId}`);

        // 记录等待时间统计
        this.recordWaitTime(Date.now() - startTime);
        return connection;
      } else if (connection) {
        await this.removeConnection(connectionId);
      }
    }

    // 检查是否需要动态扩展
    if (this.shouldScaleUp()) {
      await this.scaleUp();
    }

    // Create new connection if pool is not full
    if (this.connections.size < this.currentPoolSize) {
      try {
        const connection = await this.createConnection();
        this.recordWaitTime(Date.now() - startTime);
        return connection;
      } catch (error) {
        this.connectionFailureCount++;
        this.logger.error('Failed to create new connection', error as Error);
        // 如果创建连接失败，尝试等待现有连接
      }
    }

    // Wait for a connection to become available with timeout
    return new Promise((resolve, reject) => {
      const request: PendingRequest = {
        resolve: (connection) => {
          this.recordWaitTime(Date.now() - startTime);
          resolve(connection);
        },
        reject,
        timestamp: startTime
      };

      this.pendingRequests.push(request);

      const timeout = setTimeout(() => {
        const index = this.pendingRequests.indexOf(request);
        if (index !== -1) {
          this.pendingRequests.splice(index, 1);
        }
        reject(new ConnectionError('No connections available in pool and timeout reached'));
      }, this.poolConfig.acquireTimeout);

      const onConnectionReturned = () => {
        if (this.availableConnections.length > 0 && this.pendingRequests.length > 0) {
          const pendingRequest = this.pendingRequests.shift();
          if (pendingRequest) {
            clearTimeout(timeout);
            this.removeListener('connectionReturned', onConnectionReturned);

            // 直接获取可用连接，避免递归调用
            const connectionId = this.availableConnections.pop();
            if (connectionId) {
              const connection = this.connections.get(connectionId);
              if (connection && connection.isActive) {
                this.busyConnections.add(connectionId);
                connection.usageCount++;
                connection.lastUsed = Date.now();
                pendingRequest.resolve(connection);
                return;
              }
            }

            // 如果没有可用连接，拒绝请求
            pendingRequest.reject(new ConnectionError('No valid connections available'));
          }
        }
      };

      this.on('connectionReturned', onConnectionReturned);

      // 立即检查是否有可用连接
      if (this.availableConnections.length > 0) {
        onConnectionReturned();
      }
    });
  }

  private async createConnection(): Promise<PooledConnection> {
    const connectionId = `conn_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;

    try {
      this.logger.debug(`Creating new connection ${connectionId}`);

      const connection = await connect(this.buildConnectionUrl(), this.buildConnectionOptions());
      const channel = await connection.createChannel();

      const pooledConnection: PooledConnection = {
        id: connectionId,
        connection: connection as any,
        channel,
        isActive: true,
        lastUsed: Date.now(),
        createdAt: Date.now(),
        usageCount: 1,
      };

      // Set up connection event handlers
      connection.on('error', (error: Error) => {
        this.logger.error(`Connection ${connectionId} error`, error);
        this.handleConnectionError(connectionId, error);
      });

      connection.on('close', () => {
        this.logger.info(`Connection ${connectionId} closed`);
        this.removeConnection(connectionId).catch(error => {
          this.logger.error(`Error removing closed connection ${connectionId}`, error);
        });
      });

      channel.on('error', (error: Error) => {
        this.logger.error(`Channel error on connection ${connectionId}`, error);
        this.handleConnectionError(connectionId, error);
      });

      channel.on('close', () => {
        this.logger.debug(`Channel closed on connection ${connectionId}`);
        // 正常的 channel 关闭，不需要处理为错误
        // 只有在连接池未关闭且连接仍然存在时才标记为不可用
        if (!this.isShuttingDown && this.connections.has(connectionId)) {
          const connection = this.connections.get(connectionId)!;
          connection.isActive = false;
          this.busyConnections.add(connectionId);
          const availableIndex = this.availableConnections.indexOf(connectionId);
          if (availableIndex !== -1) {
            this.availableConnections.splice(availableIndex, 1);
          }
        }
      });

      this.connections.set(connectionId, pooledConnection);
      this.busyConnections.add(connectionId);

      // 更新统计信息
      this.connectionCreationCount++;
      this.peakConnections = Math.max(this.peakConnections, this.connections.size);

      this.logger.info(`Created connection ${connectionId}`);
      this.emit('connectionCreated', pooledConnection);

      return pooledConnection;
    } catch (error) {
      this.connectionFailureCount++;
      this.logger.error(`Failed to create connection ${connectionId}`, error as Error);
      throw new ConnectionError(`Failed to create connection: ${error}`);
    }
  }

  private async removeConnection(connectionId: string): Promise<void> {
    const connection = this.connections.get(connectionId);
    if (!connection) return;

    connection.isActive = false;
    this.connections.delete(connectionId);
    this.busyConnections.delete(connectionId);

    const availableIndex = this.availableConnections.indexOf(connectionId);
    if (availableIndex !== -1) {
      this.availableConnections.splice(availableIndex, 1);
    }

    try {
      if (connection.channel && !(connection.channel as any).connection?.destroyed) {
        await connection.channel.close();
      }
      if (connection.connection && !(connection.connection as any).connection?.destroyed) {
        await (connection.connection as any).close();
      }
    } catch (error) {
      this.logger.warn(`Error closing connection ${connectionId}`, { error });
    }

    this.logger.info(`Removed connection ${connectionId}`);
    this.emit('connectionRemoved', connection);
  }

  private handleConnectionError(connectionId: string, error: Error): void {
    this.logger.warn(`Connection ${connectionId} encountered error: ${error.message}`);
    this.removeConnection(connectionId).catch(removeError => {
      this.logger.error(`Error removing failed connection ${connectionId}`, removeError);
    });
    // 只在有监听器时才发出错误事件，避免未处理的错误
    if (this.listenerCount('error') > 0) {
      this.emit('error', error);
    }
  }

  private buildConnectionUrl(): string {
    const { host, port, username, password, virtualHost } = this.config;
    // For virtual host, we need to handle the leading slash properly
    // If virtualHost starts with '/', we keep it and encode the rest
    // Otherwise, we add '/' and encode the whole thing
    let encodedVirtualHost: string;
    if (virtualHost.startsWith('/')) {
      const pathPart = virtualHost.slice(1); // Remove leading slash
      encodedVirtualHost = encodeURIComponent(pathPart);
    } else {
      encodedVirtualHost = encodeURIComponent(virtualHost);
    }
    const protocol = this.config.sslEnabled ? 'amqps' : 'amqp';
    return `${protocol}://${username}:${password}@${host}:${port}/${encodedVirtualHost}`;
  }

  private buildConnectionOptions(): ConnectionOptions {
    const options: ConnectionOptions = {
      heartbeat: this.config.heartbeat,
      timeout: this.config.connectionTimeout,
    };

    if (this.config.sslEnabled && this.config.sslOptions) {
      options.ssl = this.config.sslOptions;
    }

    return options;
  }

  private startReaper(): void {
    this.reapTimer = setInterval(() => {
      this.reapIdleConnections().catch(error => {
        this.logger.error('Error during connection reaping', error);
      });
    }, this.poolConfig.reapInterval);
  }

  private async reapIdleConnections(): Promise<void> {
    const now = Date.now();
    const connectionsToReap: string[] = [];

    for (const [connectionId, connection] of this.connections) {
      if (
        !this.busyConnections.has(connectionId) &&
        now - connection.lastUsed > this.poolConfig.idleTimeout
      ) {
        connectionsToReap.push(connectionId);
      }
    }

    for (const connectionId of connectionsToReap) {
      this.logger.debug(`Reaping idle connection ${connectionId}`);
      await this.removeConnection(connectionId);
    }
  }

  public async shutdown(): Promise<void> {
    this.isShuttingDown = true;

    if (this.reapTimer) {
      clearInterval(this.reapTimer);
    }

    const connectionIds = Array.from(this.connections.keys());
    await Promise.all(connectionIds.map(id => this.removeConnection(id)));

    this.logger.info('Connection pool shut down');
    this.emit('shutdown');
  }

  public getStats(): {
    totalConnections: number;
    availableConnections: number;
    busyConnections: number;
    poolSize: number;
  } {
    return {
      totalConnections: this.connections.size,
      availableConnections: this.availableConnections.length,
      busyConnections: this.busyConnections.size,
      poolSize: this.poolConfig.poolSize,
    };
  }

  // 扩展的统计方法
  public getExtendedStats(): ExtendedConnectionPoolStats {
    const now = Date.now();
    const timeSinceReset = (now - this.lastStatsReset) / 1000 / 60; // 分钟

    // 计算空闲连接数
    const idleConnections = this.availableConnections.filter(id => {
      const connection = this.connections.get(id);
      return connection && (now - connection.lastUsed) > 60000; // 1分钟未使用
    }).length;

    return {
      totalConnections: this.connections.size,
      availableConnections: this.availableConnections.length,
      busyConnections: this.busyConnections.size,
      poolSize: this.currentPoolSize,
      pendingRequests: this.pendingRequests.length,
      connectionCreationRate: timeSinceReset > 0 ? this.connectionCreationCount / timeSinceReset : 0,
      connectionFailureRate: timeSinceReset > 0 ? this.connectionFailureCount / timeSinceReset : 0,
      averageWaitTime: this.waitTimeCount > 0 ? this.totalWaitTime / this.waitTimeCount : 0,
      peakConnections: this.peakConnections,
      idleConnections,
      connectionUtilization: this.connections.size > 0 ? this.busyConnections.size / this.connections.size : 0,
      lastScaleEvent: this.lastScaleEvent
    };
  }

  // 重置统计信息
  public resetStats(): void {
    this.connectionCreationCount = 0;
    this.connectionFailureCount = 0;
    this.totalWaitTime = 0;
    this.waitTimeCount = 0;
    this.peakConnections = this.connections.size;
    this.lastStatsReset = Date.now();
  }

  // 记录等待时间
  private recordWaitTime(waitTime: number): void {
    this.totalWaitTime += waitTime;
    this.waitTimeCount++;
  }

  // 检查是否需要扩展
  private shouldScaleUp(): boolean {
    if (!this.poolConfig.dynamicScaling) return false;
    if (this.currentPoolSize >= (this.poolConfig.maxPoolSize || 50)) return false;

    return this.pendingRequests.length >= (this.poolConfig.scaleUpThreshold || 5);
  }

  // 检查是否需要收缩
  private shouldScaleDown(): boolean {
    if (!this.poolConfig.dynamicScaling) return false;
    if (this.currentPoolSize <= (this.poolConfig.minPoolSize || 2)) return false;

    const idleCount = this.availableConnections.length;
    return idleCount >= (this.poolConfig.scaleDownThreshold || 10);
  }

  // 扩展连接池
  private async scaleUp(): Promise<void> {
    const oldSize = this.currentPoolSize;
    const step = this.poolConfig.scaleUpStep || 2;
    const maxSize = this.poolConfig.maxPoolSize || 50;

    this.currentPoolSize = Math.min(oldSize + step, maxSize);

    this.lastScaleEvent = {
      timestamp: Date.now(),
      action: 'scale-up',
      fromSize: oldSize,
      toSize: this.currentPoolSize,
      reason: `Pending requests: ${this.pendingRequests.length}`
    };

    this.logger.info(`Scaling up connection pool from ${oldSize} to ${this.currentPoolSize}`);
    this.emit('poolScaled', this.lastScaleEvent);
  }

  // 收缩连接池
  private async scaleDown(): Promise<void> {
    const oldSize = this.currentPoolSize;
    const step = this.poolConfig.scaleDownStep || 1;
    const minSize = this.poolConfig.minPoolSize || 2;

    this.currentPoolSize = Math.max(oldSize - step, minSize);

    // 移除多余的空闲连接
    const excessConnections = this.connections.size - this.currentPoolSize;
    if (excessConnections > 0) {
      const connectionsToRemove = this.availableConnections.slice(0, excessConnections);
      for (const connectionId of connectionsToRemove) {
        await this.removeConnection(connectionId);
      }
    }

    this.lastScaleEvent = {
      timestamp: Date.now(),
      action: 'scale-down',
      fromSize: oldSize,
      toSize: this.currentPoolSize,
      reason: `Idle connections: ${this.availableConnections.length}`
    };

    this.logger.info(`Scaling down connection pool from ${oldSize} to ${this.currentPoolSize}`);
    this.emit('poolScaled', this.lastScaleEvent);
  }
}
